package mysql;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;

/**
 * 找回存储在DBeaver连接中的数据库密码
 * https://blog.csdn.net/LastNight_Will/article/details/131652305
 * dbeaver源码：https://hub.fgit.cf/dbeaver/dbeaver/blob/6.3.5/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/app/DefaultSecureStorage.java
 */
public class DbeaverPassword {
    public static final String CIPHER_NAME = "AES/CBC/PKCS5Padding";
    public static final String KEY_ALGORITHM = "AES";

    private final SecretKey secretKey;
    private final Cipher cipher;

    public DbeaverPassword(SecretKey secretKey) {
        this.secretKey = secretKey;
        try {
            this.cipher = Cipher.getInstance(CIPHER_NAME);
        } catch (Exception e) {
            System.out.println("Internal error during encrypted init" + e);
            throw new RuntimeException(e);
        }
    }


    public byte[] decryptValue(byte[] value) {
        try (InputStream byteStream = new ByteArrayInputStream(value)) {
            byte[] fileIv = new byte[16];
            byteStream.read(fileIv);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(fileIv));
            try (CipherInputStream cipherIn = new CipherInputStream(byteStream, cipher)) {
                ByteArrayOutputStream resultBuffer = new ByteArrayOutputStream();
                int bufferSize = 100;
                byte[] buffer = new byte[bufferSize];
                while ((bufferSize = cipherIn.read(buffer)) != -1) {
                    resultBuffer.write(buffer, 0, bufferSize);
                }
                return resultBuffer.toByteArray();
            }

        } catch (Exception e) {
            System.out.println("Error decrypting value" + e);
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws Exception {
        // 密码文件 加密
        File file = new File("C:\\Users\\74102\\AppData\\Roaming\\DBeaverData\\workspace6\\General\\.dbeaver\\credentials-config.json");

        final byte[] LOCAL_KEY_CACHE = new byte[]{-70, -69, 74, -97, 119, 74, -72, 83, -55, 108, 45, 101, 61, -2, 84, 74};
        SecretKey aes = new SecretKeySpec(LOCAL_KEY_CACHE, KEY_ALGORITHM);
        DbeaverPassword encryptor = new DbeaverPassword(aes);
        // byte[] credentialsConfigBytesSecret = Files.readAllBytes(Paths.get(args[0]));
        byte[] credentialsConfigBytesSecret = Files.readAllBytes(file.toPath());
        byte[] credentialsConfigBytesPlain = encryptor.decryptValue(credentialsConfigBytesSecret);
        String jsonString = new String(credentialsConfigBytesPlain);

        JSONObject jsonObject = JSONObject.parseObject(jsonString);

        // 连接信息文件 未加密 connections name
        File connectionsFile = new File(file.getParentFile(), "data-sources.json");
        if (connectionsFile.exists() && connectionsFile.isFile()) {

            byte[] bytes = Files.readAllBytes(connectionsFile.toPath());
            // byte[]转换成String
            String connectionsStr = new String(bytes, "UTF-8");
            JSONObject connectionsJsonObject = JSONObject.parseObject(connectionsStr);
            JSONObject connectionsObj = connectionsJsonObject.getJSONObject("connections");
            if (connectionsObj == null) {
                return;
            }

            /*JSONArray jsonArray = JSONObject.parseArray(jsonString);
            for (Object obj : jsonArray) {
                // 将 Object 对象转换为 JSONObject
                *//*String jsonStr = JSON.toJSONString(obj);
                JSONObject passwordObj = JSON.parseObject(jsonStr);*//*
                JSONObject passwordObj = (JSONObject) JSON.toJSON(obj);
            }*/

            // JSONObject 即map
            jsonObject.forEach((k,v) -> {
                JSONObject o = connectionsObj.getJSONObject(k);
                if (o != null) {
                    JSONObject passwordObj = (JSONObject) JSON.toJSON(v);
                    passwordObj.put("connection", o);
                }
            });

        }

        // Fastjson美化json字符串格式 https://blog.51cto.com/hspbc/5052416
        System.out.println(JSON.toJSONString(jsonObject, true));
    }

}
